
package com.lixinlei.log.util;

import java.util.Collection;
import java.util.HashMap;

import org.slf4j.Logger;

import com.alibaba.fastjson.JSONObject;

/**
 * 日志工具类
 */
public final class LogUtil {

    public static String toJsonString(Object obj) {
        return JSONObject.toJSONString(obj);
    }

    @SuppressWarnings("rawtypes")
    protected static void appendObject(StringBuffer sb, int index, Object obj) {
        if (obj instanceof Collection) {
            sb.append(" #").append(index).append(":size=").append(((Collection) obj).size())
                    .append(",").append(toJsonString(obj));
        } else {
            sb.append(" #").append(index).append(":").append(toJsonString(obj));
        }
    }

    protected static void appendObjects(StringBuffer sb, Object... objs) {
        for (int i = 0; i < objs.length; i++) {
            Object obj = objs[i];
            appendObject(sb, i, obj);
        }
    }

    protected static void appendMethod(StringBuffer sb, StackTraceElement ste) {
        String methodName = ste.getMethodName();
        int lineNumber = ste.getLineNumber();
        sb.append(methodName).append(":").append(lineNumber);
    }

    protected static String toString(String message, Object... objs) {
        StringBuffer sb = new StringBuffer();
        StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        if (ste.length > 3) {
            appendMethod(sb, ste[3]);
        }

        sb.append(" ").append(message);
        appendObjects(sb, objs);

        return sb.toString();
    }

    public static void trace(Logger logger, String message, Object... objs) {
        if (logger.isTraceEnabled()) {
            logger.trace(toString(message, objs));
        }
    }

    public static void traceEx(Logger logger, String message, Exception e) {
        if (logger.isTraceEnabled()) {
            logger.trace(toString(message), e);
        }
    }

    public static void debug(Logger logger, String message, Object... objs) {
        if (logger.isDebugEnabled()) {
            logger.debug(toString(message, objs));
        }
    }

    public static void debugEx(Logger logger, String message, Exception e) {
        if (logger.isDebugEnabled()) {
            logger.debug(toString(message), e);
        }
    }

    public static void info(Logger logger, String message, Object... objs) {
        if (logger.isInfoEnabled()) {
            logger.info(toString(message, objs));
        }
    }

    public static void infoEx(Logger logger, String message, Exception e) {
        if (logger.isInfoEnabled()) {
            logger.info(toString(message), e);
        }
    }

    public static void warn(Logger logger, String message, Object... objs) {
        if (logger.isWarnEnabled()) {
            logger.warn(toString(message, objs));
        }
    }

    public static void warnEx(Logger logger, String message, Exception e) {
        if (logger.isWarnEnabled()) {
            logger.warn(toString(message), e);
        }
    }

    public static void error(Logger logger, String message, Object... objs) {
        if (logger.isErrorEnabled()) {
            logger.error(toString(message, objs));
        }
    }

    public static void errorEx(Logger logger, String message, Exception e) {
        if (logger.isErrorEnabled()) {
            logger.error(toString(message), e);
        }
    }

    protected static String toString(Object... objs) {
        StringBuffer sb = new StringBuffer();

        StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        if (ste.length > 3) {
            appendMethod(sb, ste[3]);
        }

        appendObjects(sb, objs);
        return sb.toString();
    }

    public static void trace(Logger logger, Object... objs) {
        if (logger.isTraceEnabled()) {
            logger.trace(toString(objs));
        }
    }

    public static void debug(Logger logger, Object... objs) {
        if (logger.isDebugEnabled()) {
            logger.debug(toString(objs));
        }
    }

    public static void info(Logger logger, Object... objs) {
        if (logger.isInfoEnabled()) {
            logger.info(toString(objs));
        }
    }

    public static void warn(Logger logger, Object... objs) {
        if (logger.isWarnEnabled()) {
            logger.warn(toString(objs));
        }
    }

    public static void error(Logger logger, Object... objs) {
        if (logger.isErrorEnabled()) {
            logger.error(toString(objs));
        }
    }

    static ThreadLocal<HashMap<String, Long>> threadLocal = new ThreadLocal<HashMap<String, Long>>();

    public static void enter(Logger logger, Object... objs) {
        StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        StringBuffer sb = new StringBuffer();
        String key = "";
        if (ste.length > 2) {
            appendMethod(sb, ste[2]);
            key = ste[2].getClassName() + "." + ste[2].getMethodName();
        }
        sb.append(" enter");
        appendObjects(sb, objs);
        logger.debug(sb.toString());

        HashMap<String, Long> map = threadLocal.get();
        if (map == null) {
            map = new HashMap<String, Long>();
            threadLocal.set(map);
        }
        map.put(key, System.currentTimeMillis());
    }

    public static void leave(Logger logger, Object... objs) {
        StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        String key = "";
        StringBuffer sb = new StringBuffer();
        if (ste.length > 2) {
            appendMethod(sb, ste[2]);
            key = ste[2].getClassName() + "." + ste[2].getMethodName();
        }
        sb.append(" leave");
        HashMap<String, Long> map = threadLocal.get();
        if (map != null) {
            Long begin = map.remove(key);
            if (begin != null) {
                long cost = System.currentTimeMillis() - begin.longValue();
                sb.append(" ").append(cost).append("ms");
            }
        }
        appendObjects(sb, objs);
        logger.debug(sb.toString());
    }

    public static String currentMethod() {
        StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        String method = "";
        if (ste.length > 2) {
            method = ste[2].getMethodName();
        }
        return method;
    }

}
